import axios from 'axios';
import _ from 'lodash';
import errorHandle from './errorHandle';
import { Message, Loading } from 'element-ui';
import { errorCode } from '@/utils/index';

// loading对象
let loading;

// 当前正在请求的数量
let requestCount = 0;

// 清除延时显示的loading
const clearTimeoutByUrl = (url, requestList) => {
  for (let item in requestList) {
    if (url === requestList[item]['url']) {
      clearTimeout(requestList[item]['timeId']);
    }
  }
};

// 存储请求接口
let requestTimeIdList = [];

//显示loading
function showLoading(text, target) {
  // 避免重复创建loading对象
  if (requestCount === 0 && !loading) {
    loading = Loading.service({
      lock: true,
      spinner: 'el-icon-loading',
      customClass: 'custom-loading',
      text,
      background: 'rgba(0, 0, 0, 0.7)',
      target: target || 'body'
    });
  }
  requestCount++;
}

// 隐藏loading
function hideLoading() {
  // 请求数量小于等于0 证明没有开启loading
  if (requestCount <= 0) return;

  requestCount--;
  // 防止请求数量小于0，做个0值保护
  requestCount = Math.max(requestCount, 0);
  if (requestCount === 0) {
    toHideLoading();
  }
}

// 利用防抖来处理连续请求时，loading闪烁问题
let toHideLoading = _.debounce(() => {
  loading.close();
  loading = null;
}, 300);

class HttpRequest {
  // 获取基础配置
  getInsideConfig() {
    const config = {
      timeout: 30000 //请求超时时间
    };

    return config;
  }

  // 设定拦截器
  interceptors(instance) {
    // 请求拦截器
    instance.interceptors.request.use(
      config => {
        if (!config.headers.hideLoading) {
          // 开启loading
          let loadingText = '请求中，请稍候……';
          if (config.headers.loadingText) {
            loadingText = decodeURI(config.headers.loadingText);
          }
          // 添加延时显示loading方式，请求时间大于100ms时才显示loading
          const timeId = setTimeout(() => {
            showLoading(loadingText);
          }, 100);
          requestTimeIdList.push({
            timeId: timeId,
            url: config.url
          });
        }

        // 请求携带token
        if (localStorage.getItem('token')) {
          config.headers.token = localStorage.getItem('token');
        }

        return config;
      },
      err => {
        // 有设置显示loading时，关闭loading
        if (!err.config.headers.hideLoading) {
          clearTimeoutByUrl(err.config.url, requestTimeIdList);
          hideLoading();
        }
        errorHandle(err);
        return Promise.reject(err);
      }
    );

    // 响应拦截器
    instance.interceptors.response.use(
      res => {
        // 有设置显示loading时，关闭loading
        if (!res.config.headers.hideLoading) {
          clearTimeoutByUrl(res.config.url, requestTimeIdList);
          hideLoading();
        }

        if (res.status === 200) {
          let code = res.data.status;
          if (code === 200) {
            return Promise.resolve(res.data);
          } else {
            if (code === 9) {
              //失败后页面有后续操作的
              return Promise.resolve(res.data);
            } else {
              let msg = res.data.message;
              Message({
                type: 'error',
                message: errorCode(msg)
              });
              return Promise.reject(res);
            }
          }
        } else {
          return Promise.reject(res);
        }
      },
      err => {
        // 有设置显示loading时，关闭loading
        if (!err.config.headers.hideLoading) {
          clearTimeoutByUrl(err.config.url, requestTimeIdList);
          hideLoading();
        }

        errorHandle(err);
        return Promise.reject(err);
      }
    );
  }

  // 创建实例
  request(options) {
    const instance = axios.create();
    const newOptions = Object.assign(this.getInsideConfig(), options);
    this.interceptors(instance);
    return instance(newOptions);
  }

  // get方法
  get(url, data) {
    const options = Object.assign(
      {
        method: 'get',
        url
      },
      data
    );
    return this.request(options);
  }

  // post方法
  post(url, data) {
    return this.request({
      method: 'post',
      url,
      data
    });
  }

  // put方法
  put(url, data) {
    return this.request({
      method: 'put',
      url,
      data
    });
  }

  // delete方法
  delete(url, data) {
    return this.request({
      method: 'delete',
      url,
      data
    });
  }
}

export default new HttpRequest();
